package packet

import (
	"encoding/binary"
	"time"
)

const (
	// ControlLoopbackEnabled indicates that the control station needs to send comparison results
	ControlLoopbackEnabled = 0xF0
	// ControlLoopbackDisabled indicates that the control station does not need to send comparison results
	ControlLoopbackDisabled = 0x0F
)

// ControlFrameData represents the data portion of a control frame packet
type ControlFrameData struct {
	LoopbackFlag byte   // 小环标识 (1 byte): 0xF0 or 0x0F
	FrameLength  uint32 // 遥控帧长度 (4 bytes)
	SendDate     uint16 // 发遥控日期 (2 bytes) - 北京时积日
	SendTime     uint32 // 发遥控时间 (4 bytes) - 0xFFFFFFFF for immediate send
	ControlFrame []byte // 遥控帧数据
}

// NewControlFrameData creates a new control frame data structure
func NewControlFrameData(loopbackEnabled bool, controlFrame []byte, immediateExecution bool) *ControlFrameData {
	data := &ControlFrameData{
		LoopbackFlag: ControlLoopbackDisabled,
		FrameLength:  uint32(len(controlFrame)),
		ControlFrame: controlFrame,
	}

	if loopbackEnabled {
		data.LoopbackFlag = ControlLoopbackEnabled
	}

	// Calculate Beijing time
	now := time.Now().In(time.FixedZone("CST", 8*3600))
	startOfYear := time.Date(now.Year(), 1, 1, 0, 0, 0, 0, now.Location())
	dayOfYear := uint16(now.Sub(startOfYear).Hours()/24) + 1

	data.SendDate = dayOfYear

	if immediateExecution {
		data.SendTime = 0xFFFFFFFF
	} else {
		// Convert current time to seconds since midnight
		midnight := time.Date(now.Year(), now.Month(), now.Day(), 0, 0, 0, 0, now.Location())
		data.SendTime = uint32(now.Sub(midnight).Seconds())
	}

	return data
}

// Bytes converts the control frame data to a byte slice
func (c *ControlFrameData) Bytes() []byte {
	// Calculate total length: 1 + 4 + 2 + 4 + len(ControlFrame)
	totalLen := 11 + len(c.ControlFrame)
	data := make([]byte, totalLen)

	// Write loopback flag
	data[0] = c.LoopbackFlag

	// Write frame length
	binary.LittleEndian.PutUint32(data[1:5], c.FrameLength)

	// Write send date
	binary.LittleEndian.PutUint16(data[5:7], c.SendDate)

	// Write send time
	binary.LittleEndian.PutUint32(data[7:11], c.SendTime)

	// Write control frame data
	copy(data[11:], c.ControlFrame)

	return data
}

// NewControlPacket creates a new control packet with the specified parameters
func NewControlPacket(sourceID uint32, destID uint32, targetCode []byte, loopbackEnabled bool, controlFrame []byte, immediateExecution bool) *DataPacket {
	controlData := NewControlFrameData(loopbackEnabled, controlFrame, immediateExecution)
	return NewDataPacket(sourceID, destID, targetCode, controlData.Bytes())
}

// ParseControlFrameData parses a byte slice into a control frame data structure
func ParseControlFrameData(data []byte) (*ControlFrameData, error) {
	if len(data) < 11 {
		return nil, ErrInvalidDataLength
	}

	frameLength := binary.LittleEndian.Uint32(data[1:5])
	if len(data) < int(11+frameLength) {
		return nil, ErrInvalidDataLength
	}

	return &ControlFrameData{
		LoopbackFlag: data[0],
		FrameLength:  frameLength,
		SendDate:     binary.LittleEndian.Uint16(data[5:7]),
		SendTime:     binary.LittleEndian.Uint32(data[7:11]),
		ControlFrame: data[11 : 11+frameLength],
	}, nil
}
